using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;

namespace Unity.Entities
{
    /// <summary>
    /// Base interface for Aspects, a higher level combination for components.
    /// </summary>
    /// <remarks>
    /// Implement IAspect on a struct with any number of <see cref="RefRW{T}"/> fields.
    /// A <see cref="RefRW{T}"/> field may use these attributes:
    ///     [<see cref="OptionalAttribute"/>]
    ///         Make the component optional. Field <see cref="RefRW{T}.IsValid"/> will be true if the component is present on the current entity.
    ///     [<see cref="Collections.ReadOnlyAttribute"/>]
    ///         Make the component read-only when building an entity query that uses the aspect.
    ///         The field <see cref="RefRW{T}.ValueRW"/> will break the safety checks. Use <see cref="RefRW{T}.ValueRO"/> instead.
    /// </remarks>
    [Obsolete("IAspect is now deprecated.  Please use component and query APIs directly.")]
    public interface IAspect : IQueryTypeParameter
    {
    }

    /// <summary>
    /// Interface provided by codegen to allow an Aspect to be created from a SystemState reference.
    /// Only used/generated by internal Unity codegen.
    /// </summary>
    /// <typeparam name="T">Type of aspect.</typeparam>
    [Obsolete("IAspectCreate is now deprecated.  Please use component and query APIs directly.")]
    public interface IAspectCreate<T> : IQueryTypeParameter where T : IAspect
    {
        /// <summary>
        /// Create an Aspect that reflects the data attached to an Entity and provides methods and properties for interacting with
        /// sets of data on the Entity.
        /// </summary>
        /// <param name="entity">Entity that this Aspect will reflect.</param>
        /// <param name="system">SystemState for the system where the Aspect originates from. You should only use Aspects
        /// in their originating system.</param>
        /// <returns>Instance of Aspect of this type for the Entity.</returns>
        T CreateAspect(Entity entity, ref SystemState system);

        /// <summary>
        /// Add the query component requirements of this aspect to NativeLists.
        /// </summary>
        /// <param name="all">The UnsafeList to add the "All" ComponentTypes requirements to</param>
        void AddComponentRequirementsTo(ref UnsafeList<ComponentType> all);

        /// <summary>
        /// Complete all dependencies for this aspect before a read-only operation.
        /// </summary>
        /// <param name="state">SystemState for the system from which the Aspect originates. You should only use Aspects in their originating system.</param>
        void CompleteDependencyBeforeRO(ref SystemState state);

        /// <summary>
        /// Complete all dependencies for this aspect before a read-write operation.
        /// </summary>
        /// <param name="state">SystemState for the system from which the Aspect originates. You should only use Aspects in their originating system.</param>
        void CompleteDependencyBeforeRW(ref SystemState state);
    }

    /// <summary>
    /// Disable the source generator for an Aspect type, i.e. a struct that implements IAspect
    /// It is up to the user to write the required code to complete all the functionalities needed by an Aspect.
    /// Disabling the source generator should not be used outside of development purposes.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct)]
    public class DisableGenerationAttribute : Attribute
    {
    }

    /// <summary>
    /// When used on an aspect's ComponentDataRef field, marks that component type as optional.
    /// </summary>
    /// <remarks>
    /// The DOTS source generator handles the generation of the query using this attribute.
    /// A ComponentDataRef may also be marked read-only by using the attribute [Unity.Collections.ReadOnly].
    ///
    /// This attribute is not intended to be used with <see cref="DynamicBuffer{T}"/> components.
    /// </remarks>
    [AttributeUsage(AttributeTargets.Field)]
    public class OptionalAttribute : Attribute
    {
    }
}
